package com.stylefeng.guns.modular.fileManage.service.impl;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.stylefeng.guns.common.exception.BizExceptionEnum;
import com.stylefeng.guns.common.exception.BussinessException;
import com.stylefeng.guns.common.persistence.model.ZyTea;
import com.stylefeng.guns.config.properties.GunsProperties;
import com.stylefeng.guns.core.qr.MatrixToImageWriter;
import com.stylefeng.guns.modular.fileManage.dao.ZyTeaDao;
import com.stylefeng.guns.modular.fileManage.enums.QrCodeEnums;
import com.stylefeng.guns.modular.fileManage.service.QrCodeService;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author LPh
 */
@Service
public class QrCodeServiceImpl implements QrCodeService {

    private Logger log = LoggerFactory.getLogger(QrCodeServiceImpl.class);

    private boolean havePath = false;

    private final String TEMP_ZIP_NAME = "temporary.zip";

    @Value("${guns.front-view-url}")
    private String url;

    @Autowired
    GunsProperties gunsProperties;

    @Autowired
    private QrCodeServiceImpl qrCodeServiceImpl;

    @Override
    public void createCode(String url, String teaId, String teaName) throws BussinessException, Exception {

        if (StringUtils.isBlank(url) || StringUtils.isBlank(teaId) || StringUtils.isBlank(teaName)) {
            log.info("【生成二维码】参数异常：url={}，teaId={}，teaName={}", url, teaId, teaName);
            throw new BussinessException(BizExceptionEnum.CODE_PARAM_ERROR);
        }

        log.info("【生成二维码】传入参数：url={}，teaId={}，teaName={}", url, teaId, teaName);
        //若文件夹不存在就创建目录
        File file = new File(gunsProperties.getQaCodePath());
        if (!file.exists()) {
            file.mkdirs();
        }
        Path path = new File(createPath(gunsProperties.getQaCodePath()) + teaId + "_" +  teaName + ".png").toPath();

        log.info("【生成二维码】保存路径：path={}", path);

        String codeContent = url + teaId;
        log.info("【生成二维码】二维码内容：" + codeContent);

        //定义二维码参数
        HashMap hint = new HashMap(16);
        hint.put(EncodeHintType.CHARACTER_SET, "utf-8");
        hint.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
        hint.put(EncodeHintType.MARGIN, QrCodeEnums.CODE_MARGIN.getCode());

        BitMatrix bitMatrix = new MultiFormatWriter().encode(codeContent, BarcodeFormat.QR_CODE, QrCodeEnums.CODE_WIDTH.getCode(), QrCodeEnums.CODE_HEIGHT.getCode(), hint);

        MatrixToImageWriter.writeToPath(bitMatrix, QrCodeEnums.CODE_FORMAT.getMessage(), path);

    }

    @Override
    public ResponseEntity<byte[]> download(HttpServletRequest request, String teaId, String teaName) throws BussinessException, Exception {

        if (StringUtils.isBlank(teaId) || StringUtils.isBlank(teaName)) {
            log.info("【下载二维码】参数异常，teaId={}，teaName={}", teaId, teaName);
            throw new BussinessException(BizExceptionEnum.CODE_PARAM_ERROR);
        }

        String path = gunsProperties.getQaCodePath() + teaId + "_" +  teaName + ".png";

        if (StringUtils.isBlank(path)) {
            log.info("【下载二维码】文件不存在，path={}", path);
            throw new BussinessException(BizExceptionEnum.CODE_FILE_NO_EXSITS);
        }
        File file = new File(path);
        log.info("【下载二维码】path:{}", path);
        byte[] body = null;
        InputStream is = new FileInputStream(file);
        body = new byte[is.available()];

        is.read(body);
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Disposition", "attchement;filename=" +
                new String(
                        (teaName + "_" + teaId + ".png").getBytes("utf-8"),
                        "ISO-8859-1"));

        HttpStatus statusCode = HttpStatus.OK;

        ResponseEntity<byte[]> entity = new ResponseEntity<byte[]>(body, headers, statusCode);
        return entity;
    }

    /**
     * 创建目录
     *
     * @param path 指定目录
     * @return 目录路径
     */
    public String createPath(String path) throws BussinessException {
        if (havePath == false) {
            File file = new File(path);
            file.mkdirs();
            havePath = true;
            log.info("【生成二维码】目录生成成功：{}", path);
        }
        return path;
    }

    /**
     * 批量下载二维码
     *
     * @param teaList
     * @return
     * @throws Exception
     */
    public ResponseEntity<byte[]> downloadList(List<ZyTea> teaList) throws Exception {
        //参数校验
        if (teaList == null || teaList.size() < 1) {
            log.info("【下载二维码】参数异常，teaList={}", teaList);
            throw new BussinessException(BizExceptionEnum.CODE_PARAM_ERROR);
        }
        // 先将所有文件压缩成一个压缩包 io流传输到本地
        File[] srcfile = new File[teaList.size()];
        for (int i = 0; i < teaList.size(); i++) {
            String picUrl = gunsProperties.getQaCodePath() +  teaList.get(i).getId() + "_" + teaList.get(i).getName() + ".png";
            File path = new File(picUrl);
            if (!path.exists()) {
                //如果没有这张二维码 就生成这张二维码
                qrCodeServiceImpl.createCode(url, teaList.get(i).getId().toString(), teaList.get(i).getName());
                log.info("【创建二维码图片】 id={}" + teaList.get(i).getId());
            }
            srcfile[i] = path;
        }

        //设置压缩包保存路径
        String temporaryPath = gunsProperties.getTempPath() + TEMP_ZIP_NAME;
        //先判断文件夹是否存在
        File zipfile = new File(temporaryPath);
        if (!zipfile.getParentFile().exists()) {
            //如果文件夹不存在创建文件夹
            zipfile.getParentFile().mkdirs();
        }
        //存放压缩包
        byte[] buf = new byte[1024];

        //ZipOutputStream类：完成文件或文件夹的压缩
        ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipfile));
        for (int i = 0; i < srcfile.length; i++) {
            FileInputStream in = new FileInputStream(srcfile[i]);
            out.putNextEntry(new ZipEntry(srcfile[i].getName()));
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
            out.closeEntry();
            in.close();
        }
        out.close();

        //先从生成的zip地址下载到本地 再删除zip文件
        File file = new File(temporaryPath);
        byte[] body = null;
        InputStream is = new FileInputStream(file);
        body = new byte[is.available()];

        is.read(body);
        //写一个时间戳来命名下载文件
        SimpleDateFormat smf = new SimpleDateFormat("yyyyMMddHHmmss");
        String defaultName = smf.format(new Date());
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Disposition", "attchement;filename=" +
                new String(
                        (defaultName + ".zip").getBytes("utf-8"),
                        "ISO-8859-1"));

        HttpStatus statusCode = HttpStatus.OK;

        ResponseEntity<byte[]> entity = new ResponseEntity<byte[]>(body, headers, statusCode);

        return entity;
    }

}
